package com.ikun.kunpicturebackend.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ikun.kunpicturebackend.api.aliyunai.model.CreateOutPaintingTaskRequest;
import com.ikun.kunpicturebackend.api.aliyunai.model.CreateOutPaintingTaskResponse;
import com.ikun.kunpicturebackend.api.aliyunai.sub.AliYunAiApi;
import com.ikun.kunpicturebackend.domain.Picture;
import com.ikun.kunpicturebackend.domain.Space;
import com.ikun.kunpicturebackend.domain.User;
import com.ikun.kunpicturebackend.exception.BusinessException;
import com.ikun.kunpicturebackend.exception.ErrorCode;
import com.ikun.kunpicturebackend.exception.ThrowUtils;
import com.ikun.kunpicturebackend.manager.upload.CosManager;
import com.ikun.kunpicturebackend.manager.upload.FilePictureUpload;
import com.ikun.kunpicturebackend.manager.upload.PictureUploadTemplate;
import com.ikun.kunpicturebackend.manager.upload.UrlPictureUpload;
import com.ikun.kunpicturebackend.model.dto.file.PictureUploadResult;
import com.ikun.kunpicturebackend.model.dto.picture.*;
import com.ikun.kunpicturebackend.model.enums.PictureReviewStatusEnum;
import com.ikun.kunpicturebackend.model.vo.PictureVO;
import com.ikun.kunpicturebackend.model.vo.UserVO;
import com.ikun.kunpicturebackend.service.PictureService;
import com.ikun.kunpicturebackend.mapper.PictureMapper;
import com.ikun.kunpicturebackend.service.SpaceService;
import com.ikun.kunpicturebackend.service.UserService;
import com.ikun.kunpicturebackend.utils.ColorSimilarUtils;
import lombok.extern.slf4j.Slf4j;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.aop.framework.AopContext;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.awt.*;
import java.io.IOException;
import java.util.*;
import java.util.List;
import java.util.stream.Collectors;

/**
* @author 32144
* @description 针对表【picture(图片)】的数据库操作Service实现
* @createDate 2025-09-26 16:09:08
*/
@Service
@Slf4j
public class PictureServiceImpl extends ServiceImpl<PictureMapper, Picture>
    implements PictureService{

    @Resource
    private FilePictureUpload filePictureUpload;

    @Resource
    private UrlPictureUpload urlPictureUpload;

    @Resource
    private TransactionTemplate transactionTemplate;

    @Resource
    private UserService userService;

    @Resource
    private CosManager cosManager;

    @Resource
    private SpaceService spaceService;

    @Resource
    private AliYunAiApi aliYunAiApi;

    @Override
    public PictureVO uploadPicture(Object inputSource, PictureUploadRequest request, User loginUser) {
        // 1.参数校验
        ThrowUtils.throwIf(loginUser == null, ErrorCode.NO_AUTH_ERROR, "未登录");
        ThrowUtils.throwIf(inputSource == null, ErrorCode.PARAMS_ERROR);
        ThrowUtils.throwIf(request == null, ErrorCode.PARAMS_ERROR);

        // 空间权限校验
        // 只能向公共图库上传图片或自己的私有空间
        Long spaceId = request.getSpaceId();
        if (spaceId != null){
            Space space = spaceService.getById(spaceId);
            ThrowUtils.throwIf(space == null, ErrorCode.NOT_FOUND_ERROR, "空间不存在");
//            ThrowUtils.throwIf(!Objects.equals(space.getUserId(), loginUser.getId()), ErrorCode.NO_AUTH_ERROR, "没有空间权限");
            // 校验空间额度
            ThrowUtils.throwIf(space.getTotalSize() >= space.getMaxSize(), ErrorCode.OPERATION_ERROR, "空间大小不足");
            ThrowUtils.throwIf(space.getTotalCount() >= space.getMaxCount(), ErrorCode.OPERATION_ERROR, "空间条数不足");
        }

        // 2.上传图片，得到信息
        String prefix;
        if (spaceId == null) {
            // 2.1 构造上传路径前缀，根据用户id划分目录：public/%s...
            prefix = String.format("public/%s", loginUser.getId());
        } else {
            //指定了空间id，根据空间id划分目录
            prefix = String.format("space/%s", spaceId);
        }

        // 2.2 得到返回结果图片信息
        // 获取图片上传模板
        PictureUploadTemplate uploadTemplate = filePictureUpload;
        // 判断是否是url
        if (inputSource instanceof String) {
            uploadTemplate = urlPictureUpload;
        }
        PictureUploadResult pictureUploadResult = uploadTemplate.uploadPicture(inputSource, prefix);

        // 3.封装返回信息
        Picture picture = new Picture();
        BeanUtil.copyProperties(pictureUploadResult, picture);

        // 设置图片名称
        if (StrUtil.isNotBlank(request.getPicName())) {
            picture.setName(request.getPicName());
        }
        picture.setUserId(loginUser.getId());

        // 3.1 获取图片id，判断是新增还是更新图片
        Long pictureId = request.getId();
        // 3.2 如果是更新图片，需要设置editTime编辑时间,更新图片需要校验图片是否存在
        if (pictureId != null && pictureId > 0){
            // 校验图片是否存在
            Picture oldPicture = getById(pictureId);
            ThrowUtils.throwIf(oldPicture == null, ErrorCode.NOT_FOUND_ERROR, "图片不存在");

            if (spaceId == null) {
                if (oldPicture.getSpaceId() != null)
                    //未指定spaceId复用图片的
                    spaceId = oldPicture.getSpaceId();
            } else {
                // 传了spaceId,必须和图片的一致
                ThrowUtils.throwIf(!spaceId.equals(oldPicture.getSpaceId()), ErrorCode.PARAMS_ERROR, "空间id不一致");
            }
            picture.setEditTime(new Date());
            picture.setId(pictureId);
        }
        //填充审核信息
        fillReviewParams(picture, loginUser);
        picture.setSpaceId(spaceId);

        // 开启事务
        Long finalSpaceId = spaceId;
        transactionTemplate.execute(status -> {
            //保存或更新到数据库
            boolean result = this.saveOrUpdate(picture);
            ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR, "图片上传失败");
            if (finalSpaceId != null) {
                // 空间id不为空，更新空间额度
                boolean update = spaceService.lambdaUpdate()
                        .eq(Space::getId, finalSpaceId)
                        .setSql("totalSize = totalSize +" + picture.getPicSize())
                        .setSql("totalCount = totalCount + 1")
                        .update();
                ThrowUtils.throwIf(!update, ErrorCode.OPERATION_ERROR, "空间额度更新失败");
            }
            return picture;
        });

        return PictureVO.domainToVO(picture);
    }

    @Override
    public QueryWrapper<Picture> getQueryWrapper(PictureQueryRequest request) {
        QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
        if (request == null) {
            return queryWrapper;
        }
        // 从request中取值
        String category = request.getCategory();
        String introduction = request.getIntroduction();
        String name = request.getName();
        List<String> tags = request.getTags();
        Integer picHeight = request.getPicHeight();
        Integer picWidth = request.getPicWidth();
        Double picScale = request.getPicScale();
        Long picSize = request.getPicSize();
        Long id = request.getId();
        String picFormat = request.getPicFormat();
        String searchText = request.getSearchText();
        Long userId = request.getUserId();
        String sortField = request.getSortField();
        String sortOrder = request.getSortOrder();
        Integer reviewStatus = request.getReviewStatus();
        Long reviewerId = request.getReviewerId();
        String reviewMessage = request.getReviewMessage();
        Long spaceId = request.getSpaceId();
        Boolean nullSpaceId = request.getNullSpaceId();
        Date startEditTime = request.getStartEditTime();
        Date endEditTime = request.getEndEditTime();


        // 判断searchText是否为空，不为空则模糊查询name和introduction
        if (StrUtil.isNotBlank(searchText)) {
            queryWrapper.and(qw -> {
                qw.like("name", searchText).or().like("introduction", searchText);
            });
        }
        queryWrapper.eq(ObjUtil.isNotNull(id), "id", id)
                .eq(ObjUtil.isNotNull(userId), "userId", userId)
                .eq(ObjUtil.isNotNull(reviewStatus), "reviewStatus", reviewStatus)
                .eq(ObjUtil.isNotNull(reviewerId), "reviewId", reviewerId)
                .like(StrUtil.isNotBlank(reviewMessage), "reviewMessage", reviewMessage)
                .like(StrUtil.isNotBlank(name), "name", name)
                .like(StrUtil.isNotBlank(introduction), "introduction", introduction)
                .like(StrUtil.isNotBlank(picFormat), "picFormat", picFormat)
                .eq(StrUtil.isNotBlank(category), "category", category)
                .eq(ObjUtil.isNotNull(picWidth), "picWidth", picWidth)
                .eq(ObjUtil.isNotNull(picHeight), "picHeight", picHeight)
                .eq(ObjUtil.isNotNull(picSize), "picSize", picSize)
                .eq(ObjUtil.isNotNull(picScale), "picScale", picScale)
                .eq(ObjUtil.isNotNull(spaceId), "spaceId", spaceId)
                .isNull(nullSpaceId, "spaceId")
                .ge(ObjUtil.isNotNull(startEditTime), "editTime", startEditTime)
                .le(ObjUtil.isNotNull(endEditTime), "editTime", endEditTime);


        //遍历标签并模糊查询标签
        //JSON数组查询
        if (CollUtil.isNotEmpty(tags)) {
            for (String tag : tags) {
                queryWrapper.like("tags", "\"" + tag + "\"");
            }
        }
        //排序
        queryWrapper.orderBy(StrUtil.isNotBlank(sortField), sortOrder.equals("ascend"), sortField);
        return queryWrapper;
    }

    @Override
    public PictureVO getPictureVO(Picture picture, HttpServletRequest request) {
        PictureVO pictureVO = PictureVO.domainToVO(picture);
        Long userId = pictureVO.getUserId();
        if (userId != null && userId > 0) {
            //查询用户信息
            User user = userService.getById(userId);
            ThrowUtils.throwIf(user == null, ErrorCode.NOT_LOGIN_ERROR, "用户不存在");
            UserVO userVO = BeanUtil.copyProperties(user, UserVO.class);
            pictureVO.setUserVO(userVO);
        }
        return pictureVO;
    }

    @Override
    public Page<PictureVO> getPictureVOPage(Page<Picture> picturePage, HttpServletRequest request) {
        // 1.从picturePage中获取记录List<Picture>
        List<Picture> pictureList = picturePage.getRecords();

        // 2.构造Page<PictureVO>,填入当前页码，每页大小，总数
        Page<PictureVO> pictureVOPage = new Page<>(picturePage.getCurrent()
                , picturePage.getSize(), picturePage.getTotal());

        // 3.记录为空直接返回Page<PictureVO>
        if (CollUtil.isEmpty(pictureList)) {
            return pictureVOPage;
        }
        // 4.对记录做转换得到List<PictureVO>
        List<PictureVO> voList = pictureList.stream().map(PictureVO::domainToVO).collect(Collectors.toList());
        // 5.从记录中获取用户id，Set<Long>
        Set<Long> userIdSet = pictureList.stream().map(Picture::getUserId).collect(Collectors.toSet());

        // 6.查询用户信息，最后转换为一个Map<Long, List<User>>
        Map<Long, List<User>> userMap = userService.listByIds(userIdSet)
                .stream().collect(Collectors.groupingBy(User::getId));

        // 7.填充List<PictureVO>中的UserVO属性
        voList.forEach(pictureVO -> {
            Long userId = pictureVO.getUserId();
            if (userMap.containsKey(userId)) {
                User user = userMap.get(userId).get(0);
                UserVO userVO = BeanUtil.copyProperties(user, UserVO.class);
                pictureVO.setUserVO(userVO);
            }
        });
        pictureVOPage.setRecords(voList);
        return pictureVOPage;
    }

    @Override
    public void validPicture(Picture picture) {
        ThrowUtils.throwIf(picture == null, ErrorCode.PARAMS_ERROR);
        // 从对象中取值
        Long id = picture.getId();
        String url = picture.getUrl();
        String introduction = picture.getIntroduction();
        // 修改数据时，id 不能为空，有参数则校验
        ThrowUtils.throwIf(ObjUtil.isNull(id), ErrorCode.PARAMS_ERROR, "id 不能为空");
        if (StrUtil.isNotBlank(url)) {
            ThrowUtils.throwIf(url.length() > 1024, ErrorCode.PARAMS_ERROR, "url 过长");
        }
        if (StrUtil.isNotBlank(introduction)) {
            ThrowUtils.throwIf(introduction.length() > 800, ErrorCode.PARAMS_ERROR, "简介过长");
        }
    }

    @Override
    public void doPictureReview(PictureReviewRequest pictureReviewRequest, User loginUser) {
        // 1.获取图片id，审核状态枚举（只能是通过或拒绝），校验参数
        Long id = pictureReviewRequest.getId();
        Integer reviewStatus = pictureReviewRequest.getReviewStatus();
        PictureReviewStatusEnum statusEnum = PictureReviewStatusEnum.getReviewStatus(reviewStatus);
        boolean flag = id == null || reviewStatus == null || statusEnum == PictureReviewStatusEnum.REVIEWING;
        ThrowUtils.throwIf(flag, ErrorCode.PARAMS_ERROR);

        // 2.查询图片，判断是否存在
        Picture oldPicture = getById(id);
        ThrowUtils.throwIf(oldPicture == null, ErrorCode.NOT_FOUND_ERROR, "图片不存在");
        // 2.1 避免重复审核
        ThrowUtils.throwIf(oldPicture.getReviewStatus().equals(reviewStatus), ErrorCode.PARAMS_ERROR, "请勿重复审核");

        // 3.更新审核状态，审核人-当前登录用户，审核时间
        Picture picture = new Picture();
        BeanUtil.copyProperties(pictureReviewRequest, picture);
        picture.setReviewerId(loginUser.getId());
        picture.setReviewTime(new Date());
        // 更新图片信息
        boolean result = updateById(picture);
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR, "审核失败");
    }

    @Override
    public void fillReviewParams(Picture picture, User loginUser) {
        if (userService.isAdmin(loginUser)) {
            // 管理员自动过审
            picture.setReviewStatus(PictureReviewStatusEnum.PASS.getValue());
            picture.setReviewerId(loginUser.getId());
            picture.setReviewMessage("管理员自动过审");
            picture.setReviewTime(new Date());
        } else {
            // 非管理员，创建或编辑都要改为待审核
            picture.setReviewStatus(PictureReviewStatusEnum.REVIEWING.getValue());
        }
    }

    @Override
    public Integer uploadPictureByBatch(PictureUploadByBatchRequest batchRequest, User loginUser) {
        // 1.1 搜索词
        String searchText = batchRequest.getSearchText();
        // 1.2 抓取数量不能超过30条
        Integer count = batchRequest.getCount();
        ThrowUtils.throwIf(count > 30, ErrorCode.PARAMS_ERROR, "抓取数量不能超过30");
        // 1.3 要抓取的地址：https://cn.bing.com/images/async?q=搜索词&mmasync=1
        String url = String.format("https://cn.bing.com/images/async?q=%s&mmasync=1", searchText);

        // 2.1 声明document对象，代表HTML页面
        Document document;
        // 2.2 尝试连接并获取document
        try {
            document = Jsoup.connect(url).get();
        } catch (IOException e) {
            log.error("获取页面失败", e);
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "获取页面失败");
        }

        // 2.3 获取元素：通过类选择器找到最外层的元素 dgControl
        Element div = document.getElementsByClass("dgControl").first();
        // 判空
        ThrowUtils.throwIf(div == null, ErrorCode.OPERATION_ERROR, "获取元素失败");

        // 2.4 从div中获取图片元素列表
        Elements imgElementList = div.select("img.mimg");
        // 成功上传数量
        int uploadCount = 0;
        // 3. 遍历图片列表
        for (Element img : imgElementList) {
            // 3.1 获取图片路径：attr("src");
            String pictureUrl = img.attr("src");
            // 判空，为空则continue
            if (StrUtil.isBlank(pictureUrl)) {
                log.info("当前链接为空，已跳过：{}", pictureUrl);
                continue;
            }
            // 3.2 处理图片上传地址，防止出现转义问题，获取“?”出现的索引
            int index = pictureUrl.indexOf("?");
            if (index > -1) {
                // 截取图片路径，处理掉“?”后面的内容
                pictureUrl = pictureUrl.substring(0, index);
            }

            // 3.3 上传图片
            // 获取图片名前缀
            String namePrefix = batchRequest.getNamePrefix();
            if (StrUtil.isBlank(namePrefix)) {
                // 默认以搜索词为前缀
                namePrefix = searchText;
            }
            try {
                PictureUploadRequest uploadRequest = new PictureUploadRequest();
                if (StrUtil.isNotBlank(namePrefix)) {
                    // 设置文件名
                    uploadRequest.setPicName(namePrefix + (uploadCount + 1));
                }
                PictureVO pictureVO = this.uploadPicture(pictureUrl, uploadRequest, loginUser);
                log.info("图片上传成功, id = {}", pictureVO.getId());
                uploadCount++;
            } catch (Exception e) {
                log.error("图片上传失败", e);
                continue;
            }
            if (uploadCount >= count) break;
        }
        return uploadCount;
    }


    @Async
    @Override
    public void clearPictureFile(Picture oldPicture) {
        String pictureUrl = oldPicture.getUrl();
        // 判断该图片是否被多条记录使用
        QueryWrapper<Picture> wrapper = new QueryWrapper<Picture>().eq("url", pictureUrl);
        long count = this.count(wrapper);
        if (count > 1)
            return;

        // 将pictureUrl中的域名去除
        String key = pictureUrl.substring(pictureUrl.indexOf(".com") + 4);
        // 删除图片
        cosManager.deleteObject(key);

        // 清理缩略图
        String thumbnailUrl = oldPicture.getThumbnailUrl();
        if (StrUtil.isNotBlank(thumbnailUrl)) {
            String thumbnailKey = thumbnailUrl.substring(thumbnailUrl.indexOf(".com") + 4);
            cosManager.deleteObject(thumbnailKey);
        }
    }

    @Override
    public void checkPictureAuth(User loginUser, Picture picture) {
        Long spaceId = picture.getSpaceId();
        Long userId = picture.getUserId();
        if (spaceId == null) {
            // 公共图片，只有图片创建人/管理员才能删除或编辑
            ThrowUtils.throwIf(!loginUser.getId().equals(userId) && !userService.isAdmin(loginUser),
                    ErrorCode.NO_AUTH_ERROR);
        } else {
            // 只能空间创建人才能操作
            ThrowUtils.throwIf(!loginUser.getId().equals(userId), ErrorCode.NO_AUTH_ERROR);
        }
    }

    @Override
    public void deletePicture(long pictureId, User loginUser) {
        // 查询图片信息
        Picture picture = getById(pictureId);
        ThrowUtils.throwIf(picture == null, ErrorCode.NOT_FOUND_ERROR, "图片不存在");

        // 检查权限
        // 改为使用注解鉴权
        // checkPictureAuth(loginUser, picture);

        // 开启事务
        transactionTemplate.execute(status -> {
            // 删除图片 数据库
            boolean result = removeById(pictureId);
            ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR, "删除图片失败");
            Long spaceId = picture.getSpaceId();
            if (spaceId != null) {
                // 释放空间额度
                boolean update = spaceService.lambdaUpdate()
                        .eq(Space::getId, spaceId)
                        .setSql("totalSize = totalSize -" + picture.getPicSize())
                        .setSql("totalCount = totalCount - 1")
                        .update();
                ThrowUtils.throwIf(!update, ErrorCode.OPERATION_ERROR, "空间额度更新失败");
            }
            return true;
        });

        // 异步清理图片 COS
        clearPictureFile(picture);
    }

    @Override
    public void editPicture(PictureEditRequest editRequest, User loginUser) {
        // 将请求转换为Picture
        Picture picture = new Picture();
        BeanUtil.copyProperties(editRequest, picture);
        // 手动转换tags
        picture.setTags(JSONUtil.toJsonStr(editRequest.getTags()));
        // 设置编辑时间
        picture.setEditTime(new Date());

        // 图片校验
        validPicture(picture);

        // 查询图片，判断是否存在
        Picture oldPicture = getById(editRequest.getId());
        ThrowUtils.throwIf(oldPicture == null, ErrorCode.NOT_FOUND_ERROR, "图片不存在");

        // 权限校验
        // 改为使用注解鉴权
        // checkPictureAuth(loginUser, oldPicture);

        // 填充审核相关参数
        fillReviewParams(picture, loginUser);

        // 操作数据库，更新图片
        boolean result = updateById(picture);
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
    }

    @Override
    public List<PictureVO> searchPictureByColor(Long spaceId, String picColor, User loginUser) {
        // 1. 参数校验
        ThrowUtils.throwIf(spaceId == null || StrUtil.isBlank(picColor), ErrorCode.PARAMS_ERROR);
        ThrowUtils.throwIf(loginUser == null, ErrorCode.NOT_LOGIN_ERROR);

        // 2. 校验空间权限
        Space space = spaceService.getById(spaceId);
        ThrowUtils.throwIf(space == null, ErrorCode.NOT_FOUND_ERROR, "空间不存在");
        ThrowUtils.throwIf(!space.getUserId().equals(loginUser.getId()), ErrorCode.NO_AUTH_ERROR, "没有空间访问权限");

        // 3. 查询该空间下所有带颜色的图片
        List<Picture> pictureList = this.lambdaQuery().eq(Picture::getSpaceId, spaceId)
                .isNotNull(Picture::getPicColor)
                .list();
        // 为空直接返回
        if (CollUtil.isEmpty(pictureList)) {
            return Collections.emptyList();
        }

        // 4.计算相似度并排序
        // 提前计算避免每张图片都计算
        Color targetColor = Color.decode(picColor);
        List<Picture> sortPictureList = pictureList.stream().sorted(Comparator.comparingDouble(picture -> {
            String color = picture.getPicColor();
            Color selectColor = Color.decode(color);
            // 计算相似度
            return ColorSimilarUtils.calculateSimilarity(targetColor, selectColor);
        })).limit(12).collect(Collectors.toList());

        // 转换为vo
        return sortPictureList.stream()
                .map(PictureVO::domainToVO)
                .collect(Collectors.toList());
    }

    @Override
    public void editPictureByBatch(PictureEditByBatchRequest pictureEditByBatchRequest, User loginUser) {
        // 获取参数
        List<Long> pictureIdList = pictureEditByBatchRequest.getPictureIdList();
        Long spaceId = pictureEditByBatchRequest.getSpaceId();
        String category = pictureEditByBatchRequest.getCategory();
        List<String> tags = pictureEditByBatchRequest.getTags();
        String nameRule = pictureEditByBatchRequest.getNameRule();

        // 1.参数校验
        ThrowUtils.throwIf(loginUser == null, ErrorCode.NO_AUTH_ERROR);
        ThrowUtils.throwIf(spaceId == null || CollUtil.isEmpty(pictureIdList), ErrorCode.PARAMS_ERROR);
        // 2.判断空间权限
        Space space = spaceService.getById(spaceId);
        ThrowUtils.throwIf(space == null, ErrorCode.NOT_FOUND_ERROR, "空间不存在");
        ThrowUtils.throwIf(!space.getUserId().equals(loginUser.getId()), ErrorCode.NO_AUTH_ERROR, "没有空间访问权限");

        // 3.查询指定图片，仅查询需要的字段
        List<Picture> pictureList = this.lambdaQuery().select(Picture::getId, Picture::getSpaceId)
                .eq(Picture::getSpaceId, spaceId)
                .in(Picture::getId, pictureIdList)
                .list();

        if (CollUtil.isEmpty(pictureList))
            return;

        // 批量重命名
        fillPictureWithNameRule(pictureList, nameRule);

        // 4.设置分类和标签
        pictureList.forEach(picture -> {
            if (StrUtil.isNotBlank(category)) {
                picture.setCategory(category);
            }
            if (CollUtil.isNotEmpty(tags)) {
                picture.setTags(JSONUtil.toJsonStr(tags));
            }
        });

        // 5.批量更新
        PictureService pictureService = (PictureService) AopContext.currentProxy();
        boolean result = pictureService.updateBatchById(pictureList);
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
    }

    @Override
    public CreateOutPaintingTaskResponse createPictureOutPaintingTask(CreatePictureOutPaintingTaskRequest request, User loginUser) {
        // 1. 获取图片id，查询数据库
        Long pictureId = request.getPictureId();

        Picture picture = Optional.ofNullable(getById(pictureId)).orElseThrow(() -> new BusinessException(ErrorCode.NOT_FOUND_ERROR));

        // 2. 权限校验
        // 改为使用注解鉴权
        // checkPictureAuth(loginUser, picture);

        // 3. 构造请求参数，调用ali
        CreateOutPaintingTaskRequest taskRequest = new CreateOutPaintingTaskRequest();
        CreateOutPaintingTaskRequest.Input input = new CreateOutPaintingTaskRequest.Input();
        input.setImageUrl(picture.getUrl());
        taskRequest.setInput(input);
        BeanUtil.copyProperties(request, taskRequest);

        return aliYunAiApi.createOutPaintingTask(taskRequest);
    }

    /**
     * 图片重命名
     * 规则：图片名{序号}
     * @param pictureList
     * @param nameRule 名称格式：图片名{序号}
     */
    private void fillPictureWithNameRule(List<Picture> pictureList, String nameRule) {
        if (StrUtil.isBlank(nameRule)) {
            return;
        }
        int count = 1;
        try {
            for (Picture picture : pictureList) {
                String pictureName = nameRule.replaceAll("\\{序号}", String.valueOf(count++));
                picture.setName(pictureName);
            }
        } catch (Exception e) {
            log.error("名称解析错误", e);
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "名称解析错误");
        }
    }
}




